﻿/* Autoduel Game
 * CS4911 Senior Design Project
 * Fall 2010 Semester
 * Ian Axelrod, Liz Ha, Andrew Muldowney, Edward Futch
 */
using System;

using AutoduelClient.GameClient;
using AutoduelClient.GameClient.Network;
using AutoduelClient.GameClient.Player;
using AutoduelClient.GameClient.World;
using AutoduelClient.GameUI;

namespace AutoduelClient
{
    /// <summary>
    /// The Client class represents the top-level of the Autoduel game client
    /// The game world is insantiated and managed from here, as well as
    /// user operations
    /// </summary>
    public class Client : SimpleClientListener
    {
		#region Static Fields (3)
		// target port of the RedDwarf server
		private const int port = 13718;

		/// <summary>
        /// The prefix for the player name on the server side
        /// </summary>
        public const String PLAYER_BIND_PREFIX = "Duelist: ";
		// target IP of the RedDwarf server
        private const string host = "localhost";
		#endregion

		#region Fields (7)
		// the player object for this client
        private Player player;

		// our world
        private World world = new World();

		// the game renderer
        private Game game;

		// login communication for RedDwarf
        private SimpleClient simpleClient;

		// lets us know whether or not the client is logged in
        private Boolean loggedIn;

		// the player's password (currently unusued)
        private string password;
		// the player's username
        private string username;
		#endregion

		#region Properties (5)
		/// <summary>
        /// Gets/Sets whether or not we are logged in
        /// </summary>
        public Boolean IsLoggedIn
        {
            get { return loggedIn; }
            set { loggedIn = value; }
        }
		/// <summary>
        /// Gets/Sets the player object for this client
        /// </summary>
        public Player Player
        {
            get { return player; }
            set { player = value; }
        }
		/// <summary>
        /// Gets/Sets the RD simpleclient
        /// </summary>
        public SimpleClient SimpleClient
        {
            get { return simpleClient; }
            set { simpleClient = value; }
        }
		/// <summary>
        /// Gets/Sets the username for this client
        /// </summary>
        public string Username
        {
            get { return username; }
            set { username = value; }
        }
		/// <summary>
        /// Gets/Set the world 
        /// </summary>
        public World World
        {
            get { return world; }
            set { world = value; }
        }
		#endregion

		#region Constructors (1)
		/// <summary>
        /// Create a client instance
        /// </summary>
        /// <param name="game">Pass along the game object</param>
        public Client(Game game)
        {
            this.game = game;
        }
		#endregion

		#region Methods (10)

		/// <summary>
        /// Admin functionality - Ban a player from the game world
        /// </summary>
        /// <param name="playerName"></param>
        public void BanPlayerByName(string playerName)
        {
            string realPlayerName = "Duelist: " + playerName;
            Player player = this.world.GetPlayerByNameServer(realPlayerName);

            if (player != null)
            {
                if (player.Name != this.player.Name)
                {
                    SendMessage(player.EncodePacket(OPCODES.ORD_BANPLAYER));
                }
                else
                {
                    this.game.ShowMessageBlocking("You can't ban yourself, dummy!", "What are you doing?", System.Windows.Forms.MessageBoxButtons.OK,
                        System.Windows.Forms.MessageBoxIcon.Information);
                }
            }
            else
            {
                this.game.ShowMessageBlocking("Unable to ban player '" + playerName + "' because he doesn't exist.", "Administration Error", System.Windows.Forms.MessageBoxButtons.OK,
                    System.Windows.Forms.MessageBoxIcon.Error);
            }
        }

		/// <summary>
        /// Callback method invoked when the client is removed
        /// from the server
        /// </summary>
        /// <param name="forced">Was the client removal unexpected from his side?</param>
        /// <param name="message">The message associated with the removal</param>
        public void Disconnected(bool forced, string message)
        {
            System.Diagnostics.Debug.WriteLine("[Client] Disconnected from server: " + message);
            this.game.ShowMessageBlocking(message, "Attention!", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
            this.game.Exit();
        }

		/// <summary>
        /// Callback from SimpleClientListener to retrieve user login credentials
        /// to send to RedDwarf server
        /// </summary>
        /// <returns>The PasswordAuthentication object used by RedDwarf</returns>
        public PasswordAuthentication GetPasswordAuthentication()
        {
            return new PasswordAuthentication(this.username, this.password);
        }

		/// <summary>
        /// Callback method invoked when this client joins
        /// a channel
        /// </summary>
        /// <param name="channel">The channel the client joined</param>
        /// <returns>A listener for that channel</returns>
        public ClientChannelListener JoinedChannel(ClientChannel channel)
        {
            System.Diagnostics.Debug.WriteLine("[Client] Joined channel: " + channel);
            return new GridChannelListener(this.game);
        }

		/// <summary>
        /// Admin functionality - Kick a player from the local game world 
        /// </summary>
        /// <param name="playerName">The player to kick</param>
        public void KickPlayerByName(string playerName)
        {
            string realPlayerName = "Duelist: " + playerName;
            Player player = this.world.GetPlayerByName(realPlayerName);

            if (player != null)
            {
                if (player.Name != this.player.Name)
                {
                    SendMessage(player.EncodePacket(OPCODES.ORD_REMPLAYER));
                }
                else
                {
                    this.game.ShowMessageBlocking("You can't kick yourself, dummy! Just exit the normal way.", "What are you doing?", System.Windows.Forms.MessageBoxButtons.OK,
                        System.Windows.Forms.MessageBoxIcon.Information);
                }
            }
            else
            {
                this.game.ShowMessageBlocking("Unable to kick player '" + playerName + "' because he doesn't exist.", "Administration Error", System.Windows.Forms.MessageBoxButtons.OK, 
                    System.Windows.Forms.MessageBoxIcon.Error);
            }
        }

		/// <summary>
        /// Callback from SimpleClientListener to notify the client that
        /// he has been logged into the RedDwarf server
        /// </summary>
        public void LoggedIn(byte[] reconnectKey)
        {
            System.Diagnostics.Debug.WriteLine("[Client] You have been logged in.");
            System.Diagnostics.Debug.WriteLine("[Client] Requesting an initial list of players in our view (including us!)...");
            this.loggedIn = true;
        }

		/// <summary>
        /// Callback from SimpleClientListener to notify the client that
        /// he was not able to log-in successfully to the RedDwarf server
        /// </summary>
        /// <param name="reason">The reason why the login failed</param>
        public void LoginFailed(string reason)
        {
            this.loggedIn = false;
            System.Diagnostics.Debug.WriteLine("[Client] Login Failed: " + reason);
        }

		/// <summary>
        /// Attempt to log-in a user to the RedDwarf server
        /// </summary>
        /// <param name="username">The username</param>
        /// <param name="password">Password associated with the username</param>
        public void LoginUser(string username, string hostname)
        {
            this.username = username;
            this.password = "ThisTextIsMeaningless"; // Irrelevant data right now
            this.simpleClient = new SimpleClient(this);
            this.simpleClient.login(hostname, port);
        }

		/// <summary>
        /// Takes in messages send from the ClientSession on the server
        /// </summary>
        /// <param name="message"></param>
        public void ReceivedMessage(byte[] message)
        {
            System.Diagnostics.Debug.WriteLine("[Client] Received message");
            this.game.Messages.Enqueue(new Packet(MSGORGNS.CLIENT, message));
        }

		/// <summary>
        /// Sends a message on behalf of the client
        /// </summary>
        /// <param name="message">The message to send</param>
        public void SendMessage(byte[] message)
        {
            this.simpleClient.SessionSend(message);
        }

		#endregion
    }
}
